home *** CD-ROM | disk | FTP | other *** search
Text File | 2009-10-11 | 88.2 KB | 2,197 lines |
- #! /usr/bin/python
-
- import fnmatch, glob, os, re, string, sys, time, cStringIO
- from optparse import OptionParser
- from ConfigParser import SafeConfigParser
-
- sys.path[0:0] = ['/usr/share/pycentral-data', '/usr/share/python']
- import pyversions
-
- try:
- SetType = set
- except NameError:
- import sets
- SetType = sets.Set
- set = sets.Set
-
- program = os.path.basename(sys.argv[0])
-
- shared_base = '/usr/share/pycentral/'
- shared_base2 = '/usr/share/pyshared/'
- pycentral_version = '0.6.11ubuntu2'
- req_pycentral_version = '0.6.11'
-
-
- def get_file_overwrite_error(existing_files):
- """
- helper that returns a error string to be passed to the user when
- local files are detected (and querries if they are local installs
- or part of another package)
- """
- from subprocess import PIPE, Popen
- l = []
- # ask dpkg what it knows about the files in question
- (stdout, stderr) = Popen(["dpkg","-S"]+existing_files,
- env={"LANG" : "C"},
- stdout=PIPE, stderr=PIPE).communicate()
- # this should never happen, dpkg should always give us
- # something but we deal with it for robustness
- if not stdout and not stderr:
- l.append("Error, can not overwrite existing files:")
- l.extend(existing_files)
- # stdout has files that belong to packages
- if stdout:
- l.append("Not overwriting files owned by other packages:")
- for line in map(string.strip, stdout.split("\n")):
- if line:
- l.append(" "+line)
- # stderr has local (or maintainer script created) files
- if stderr:
- l.append("Not overwriting local files:")
- for line in map(string.strip, stderr.split("\n")):
- if line:
- l.append(" "+line)
- return "\n".join(l)
-
- def samefs(path1, path2):
- if not (os.path.exists(path1) and os.path.exists(path2)):
- return False
- while path1 != os.path.dirname(path1):
- if os.path.ismount(path1):
- break
- path1 = os.path.dirname(path1)
- while path2 != os.path.dirname(path2):
- if os.path.ismount(path2):
- break
- path2 = os.path.dirname(path2)
- return path1 == path2
-
- def version2depends(vinfo):
- if isinstance(vinfo, set):
- vinfo = list(vinfo)
- if isinstance(vinfo, list):
- vinfo = vinfo[:]
- vinfo.sort()
- nv = [int(s) for s in vinfo[-1].split('.')]
- deps = 'python (>= %s), python (<< %d.%d)' % (vinfo[0], nv[0], nv[1]+1)
- elif vinfo in ('all', 'current'):
- supported = [d[6:] for d in pyversions.supported_versions()
- if re.match(r'python\d\.\d', d)]
- supported.sort()
- deps = 'python (>= %s)' % supported[0]
- elif vinfo == 'current_ext':
- cv = pyversions.default_version(version_only=True)
- nv = [int(s) for s in cv.split('.')]
- deps = 'python (>= %s), python (<< %d.%d)' % (cv, nv[0], nv[1]+1)
- else:
- raise ValueError, 'unknown version info %s' % vinfo
- return deps + ', python-central (>= %s)' % req_pycentral_version
-
- def third_party_dir(version):
- if version.startswith('python'):
- version = version[6:]
- if version in ('2.3', '2.4', '2.5'):
- return 'usr/lib/python' + version + '/site-packages'
- else:
- return 'usr/lib/python' + version + '/dist-packages'
-
- def build_relative_link(tgt, link):
- t = tgt.split('/')
- l = link.split('/')
- while l[0] == t[0]:
- del l[0], t[0]
- return '/'.join(['..' for i in range(len(l)-1)] + t)
-
- def read_dpkg_status(verbose=False):
- """Read the dpkg status file, return a list of packages depending
- on python-central and having a Python-Version information field."""
- packages = []
- rx = re.compile(r'\bpython-central\b')
- pkgname = version = None
- depends = ''
- status = []
- for line in file('/var/lib/dpkg/status'):
- if line.startswith('Package:'):
- if version != None and 'installed' in status:
- if 'python-support' in depends:
- pass
- elif rx.search(depends):
- packages.append((pkgname, version))
- if verbose:
- print " %s: %s (%s)" % (pkgname, version, status)
- version = None
- status = []
- pkgname = line.split(':', 1)[1].strip()
- elif line.startswith('Python-Version:'):
- version = line.split(':', 1)[1].strip()
- elif line.startswith('Depends:'):
- depends = line.split(':', 1)[1].strip()
- elif line.startswith('Status:'):
- status = line.split(':', 1)[1].strip().split()
- if version != None and 'installed' in status:
- if rx.search(depends):
- packages.append((pkgname, version))
- if verbose:
- print " %s: %s (%s)" % (pkgname, version, status)
- return packages
-
-
- class PyCentralConfigParser(SafeConfigParser):
- '''SafeConfigParser allowing mixed case, `:' and `=' in keys'''
- OPTCRE = re.compile(
- r'(?P<option>[^\s].*)'
- r'\s*(?P<vi>[:=])\s*'
- r'(?P<value>.*)$'
- )
- optionxform = str
-
- class PyCentralError(Exception):
- """Python Central Exception"""
- pass
-
- class PyCentralVersionMissingError(PyCentralError):
- """Python Central Version Missing Exception"""
- pass
-
- class PythonRuntime:
- def __init__(self, name, version, interp, prefix):
- self.name = name
- self.version = version
- if name.startswith('python'):
- self.short_name = name[6:]
- else:
- self.short_name = name
- self.interp = interp
- if version in ('2.3', '2.4', '2.5'):
- sitedir = 'site-packages/'
- else:
- sitedir = 'dist-packages/'
- if prefix.endswith('/'):
- self.prefix = prefix + sitedir
- else:
- self.prefix = prefix + '/' + sitedir
-
- def byte_compile_dirs(self, dirs, bc_option, exclude=None):
- """call compileall.py -x <exclude regexp> <dirs> according
- to bc_options"""
-
- logging.debug('\tbyte-compile directories')
- errors = False
- cmd = [self.interp, self.prefix + '/compileall.py', '-q']
- if exclude:
- cmd.extend(['-x', exclude])
- cmd.extend(dirs)
- for opt in ('standard', 'optimize'):
- if not opt in bc_option:
- continue
- if opt == 'optimize':
- cmd[1:1] = ['-O']
- rv = os.spawnv(os.P_WAIT, self.interp, cmd[1:])
- if rv:
- raise PyCentralError
-
- def byte_compile(self, files, bc_option, exclude=None, ignore_errors=False, force=False):
- errors = False
- if exclude:
- rx = re.compile(exclude)
- files2 = []
- for fn in files:
- mo = rx.search(fn)
- if mo:
- continue
- files2.append(fn)
- else:
- files2 = files
- if not files2:
- logging.info('\tno files to byte-compile')
- return
- logging.debug('\tbyte-compile files (%d/%d) %s' \
- % (len(files), len(files2), self.name))
- debug_files = files2[:min(2, len(files2))]
- if len(files2) > 2:
- debug_files.append('...')
- logging.debug('\t %s' % debug_files)
- if 'python3' in self.interp:
- cmd = [self.interp, '/usr/bin/py3_compilefiles', '-q']
- else:
- cmd = [self.interp, '/usr/bin/py_compilefiles', '-q']
- if ignore_errors:
- cmd.append('-i')
- if force:
- cmd.append('-f')
- cmd.append('-')
- for opt in ('standard', 'optimize'):
- if not opt in bc_option:
- continue
- if opt == 'optimize':
- cmd[1:1] = ['-O']
- try:
- import subprocess
- p = subprocess.Popen(cmd, bufsize=1,
- shell=False, stdin=subprocess.PIPE)
- fd = p.stdin
- except ImportError:
- p = None
- fd = os.popen(' '.join(cmd), 'w')
- for fn in files2:
- fd.write(fn + '\n')
- rv = fd.close()
- if p:
- p.wait()
- errors = p.returncode != 0
- else:
- errors = rv != None
- if errors:
- raise PyCentralError, 'error byte-compiling files (%d)' % len(files2)
-
- def remove_byte_code(self, files):
- errors = False
- logging.debug('\tremove byte-code files (%d)' % (len(files)))
- for ext in ('c', 'o'):
- for fn in files:
- fnc = fn + ext
- if os.path.exists(fnc):
- try:
- os.unlink(fnc)
- except OSError, e:
- print "Sorry", e
- errors = True
- if errors:
- raise PyCentralError, 'error removing the byte-code files'
-
- def list_byte_code(self, files):
- logging.debug('\tlist byte-code files (%d)' % (len(files)))
- for ext in ('c', 'o'):
- for fn in files:
- fnc = fn + ext
- yield fnc
-
- installed_runtimes = None
- default_runtime = None
-
- def get_installed_runtimes(with_unsupported=True):
- global installed_runtimes
- global default_runtime
-
- if not installed_runtimes:
- import glob
- installed_runtimes = []
- default_version = pyversions.default_version(version_only=True)
- supported = pyversions.supported_versions()
- old = pyversions.old_versions()
- if with_unsupported:
- unsupported = pyversions.unsupported_versions()
- else:
- unsupported = []
- for interp in glob.glob('/usr/bin/python[0-9].[0-9]'):
- if old and os.path.basename(interp) in old:
- pass
- #print "INFO: using old version '%s'" % interp
- elif unsupported and os.path.basename(interp) in unsupported:
- print "INFO: using unsupported version '%s'" % interp
- if not (os.path.basename(interp) in supported
- or (old and os.path.basename(interp) in old)
- or (unsupported and os.path.basename(interp) in unsupported)):
- # pycentral used to ignore everything it has no explicit
- # knowledge about. this causes install errors when
- # debian_defaults is not up-to-date (LP: #354228)
- if with_unsupported:
- if not interp.startswith('/usr/bin/python3'):
- print "INFO: using unknown version '%s' (debian_defaults not up-to-date?)" % interp
- else:
- print "INFO: ignoring unknown version '%s'" % interp
- continue
- version = interp[-3:]
- rt = PythonRuntime('python' + version,
- version,
- '/usr/bin/python' + version,
- '/usr/lib/python' + version)
- installed_runtimes.append(rt)
- if version == default_version:
- default_runtime = rt
- return installed_runtimes
-
- def get_default_runtime():
- get_installed_runtimes()
- return default_runtime
-
- def get_runtime_for_version(version):
- if version == 'current':
- return get_default_runtime()
- for rt in get_installed_runtimes():
- if rt.version == version:
- return rt
- return None
-
- debian_config = None
- def get_debian_config():
- global debian_config
- if debian_config is not None:
- return debian_config
-
- config = SafeConfigParser()
- fn = '/etc/python/debian_config'
- if os.path.exists(fn):
- try:
- config.readfp(open(fn))
- except Error:
- logging.error("error reading config file `%s'" % fn)
- sys.exit(1)
- # checks
- if not config.has_option('DEFAULT', 'byte-compile'):
- config.set('DEFAULT', 'byte-compile', 'standard')
- bc_option = config.get('DEFAULT', 'byte-compile')
- bc_values = set([v.strip() for v in bc_option.split(',')])
- bc_unknown = bc_values - set(['standard', 'optimize'])
- if bc_unknown:
- sys.stderr.write("%s: `%s': unknown values `%s'"
- " in `byte-compile option'\n"
- % (program, fn, ', '.join(list(bc_unknown))))
- sys.exit(1)
- config.set('DEFAULT', 'byte-compile', ', '.join(bc_values))
- if config.has_option('DEFAULT', 'overwrite-local'):
- val = config.get('DEFAULT', 'overwrite-local').strip().lower()
- overwrite_local = val in ('yes', '1', 'true')
- else:
- overwrite_local = False
- config.set('DEFAULT', 'overwrite-local', overwrite_local and '1' or '0')
- debian_config = config
- return debian_config
-
- class DebPackage:
- def __init__(self, kind, name,
- oldstyle=False, default_runtime=None,
- pkgdir=None, pkgconfig=None, parse_versions=True):
- self.kind = kind
- self.name = name
- self.version_field = None
- self.oldstyle = oldstyle
- self.parse_versions = parse_versions
- self.default_runtime = default_runtime
- self.shared_prefix = None
- self.pkgdir = pkgdir
- self.pkgconfig = pkgconfig
- self.has_shared_extension = {}
- self.has_private_extension = False
- self.has_shared_module = {}
- self.has_private_module = False
- if pkgdir:
- self.read_control()
- else:
- self.read_pyfiles()
- #self.print_info()
-
- def read_pyfiles(self):
- self.shared_files = []
- self.pylib_files = {}
- self.other_pylib_files = []
- self.private_files = []
- self.omitted_files = []
- self.pysupport_files = []
- if self.pkgdir:
- lines = []
- for root, dirs, files in os.walk(self.pkgdir):
- if root.endswith('DEBIAN'):
- continue
- if root != self.pkgdir:
- d = root[len(self.pkgdir):]
- lines.append(d)
- for name in files:
- lines.append(os.path.join(d, name))
- else:
- pass # no files in /
- else:
- config_file = '/usr/share/pyshared-data/%s' % self.name
- if self.pkgconfig:
- lines = [fn for fn, t in self.pkgconfig.items('files')]
- lines.sort()
- elif os.path.isfile(config_file):
- logging.debug("reading %s" % config_file)
- self.pkgconfig = PyCentralConfigParser()
- self.pkgconfig.optionxform = str
- self.pkgconfig.readfp(file(config_file))
- if not self.pkgconfig.has_option('pycentral', 'include-links'):
- self.pkgconfig.set('pycentral', 'include-links', '0')
- elif self.pkgconfig.get('pycentral', 'include-links') == '':
- # LP #332532, empty value in file
- self.pkgconfig.set('pycentral', 'include-links', '0')
- lines = [fn for fn, t in self.pkgconfig.items('files')]
- lines.sort()
- else:
- lines = self.read_preinst_pkgconfig()
- if lines:
- pass
- elif os.environ.has_key("PYCENTRAL_NO_DPKG_QUERY"):
- logging.debug("Not using dpkg-query as requested")
- lines = map(string.strip, open('/var/lib/dpkg/info/%s.list' % self.name).readlines())
- else:
- cmd = ['/usr/bin/dpkg-query', '-L', self.name]
- try:
- import subprocess
- p = subprocess.Popen(cmd, bufsize=1,
- shell=False, stdout=subprocess.PIPE)
- fd = p.stdout
- except ImportError:
- fd = os.popen(' '.join(cmd))
- lines = [s[:-1] for s in fd.readlines()]
- if not self.pkgconfig:
- pc = PyCentralConfigParser()
- pc.optionxform = str
- pc.add_section('python-package')
- pc.set('python-package', 'format', '1')
- pc.add_section('pycentral')
- pc.set('pycentral', 'version', req_pycentral_version)
- pc.set('pycentral', 'include-links', '0')
- pc.add_section('files')
- for line in lines:
- if os.path.isdir(line) and not os.path.islink(line):
- pc.set('files', line, 'd')
- elif os.path.exists(line):
- pc.set('files', line, 'f')
- else:
- pass # should not happen
- self.pkgconfig = pc
-
- old_shared_base = shared_base + self.name + '/site-packages/'
- found_old_base = found_base2 = False
- for line in lines:
- fn = line
- if fn.startswith(shared_base2):
- # keep _all_ files and directories
- self.shared_files.append(fn)
- if fn.endswith('.py'):
- self.has_shared_module['all'] = True
- found_base2 = True
- self.shared_prefix = shared_base2
- continue
- elif fn.startswith(old_shared_base):
- # keep _all_ files and directories
- self.shared_files.append(fn)
- if fn.endswith('.py'):
- self.has_shared_module['all'] = True
- found_old_base = True
- self.shared_prefix = old_shared_base
- continue
- elif fn.startswith('/usr/share/python-support') \
- or fn.startswith('/usr/lib/python-support'):
- self.pysupport_files.append(fn)
- continue
- elif not fn.endswith('.py') and not fn.endswith('.so'):
- if re.match(r'/usr/lib/python\d\.\d/', fn):
- self.other_pylib_files.append(fn)
- continue
- elif fn.startswith('/etc/') or fn.startswith('/usr/share/doc/'):
- # omit files in /etc and /usr/share/doc
- self.omitted_files.append(fn)
- continue
- elif re.search(r'/s?bin/', fn):
- # omit files located in directories
- self.omitted_files.append(fn)
- continue
- elif fn.startswith('/usr/lib/site-python/'):
- version = pyversions.default_version(version_only=True)
- self.pylib_files.setdefault(version, []).append(fn)
- continue
- elif re.match(r'/usr/lib/python\d\.\d/', fn):
- version = fn[15:18]
- if fn.endswith('.so'):
- self.has_shared_extension[version] = True
- if fn.endswith('.py'):
- self.has_shared_module[version] = True
- self.pylib_files.setdefault(version, []).append(fn)
- continue
- else:
- self.private_files.append(fn)
- if fn.endswith('.py'):
- self.has_private_module = True
-
- if found_old_base and found_base2:
- raise PyCentralError, \
- 'shared files found in old (%s) and new locations (%s)' % (old_shared_base, shared_base2)
-
- def read_preinst_pkgconfig(self):
- try:
- fd = open('/var/lib/dpkg/info/%s.preinst' % self.name, 'r')
- except:
- return None
- buffer = None
- for line in fd.readlines():
- if line == '[python-package]\n':
- buffer = cStringIO.StringIO()
- if line in ('PYEOF\n', 'EOF\n'):
- break
- if buffer:
- buffer.write(line)
- if buffer is None:
- return None
- self.pkgconfig = PyCentralConfigParser()
- self.pkgconfig.optionxform = str
- self.pkgconfig.readfp(cStringIO.StringIO(buffer.getvalue()))
- # never set in the preinst copy of the config file
- self.pkgconfig.set('pycentral', 'include-links', '0')
- files = [fn for fn, t in self.pkgconfig.items('files')]
- files.sort()
- return files
-
- def print_info(self, fd=sys.stdout):
- fd.write('Package: %s\n' % self.name)
- fd.write(' shared files :%4d\n' % len(self.shared_files))
- fd.write(' private files :%4d\n' % len(self.private_files))
- for ver, files in self.pylib_files.items():
- fd.write(' pylib%s files:%4d\n' % (ver, len(files)))
-
- def read_control(self):
- """read the debian/control file, extract the XS-Python-Version
- field; check that XB-Python-Version exists for the package."""
- if not os.path.exists('debian/control'):
- raise PyCentralError, "debian/control not found"
- self.version_field = None
- self.sversion_field = None
- try:
- section = None
- for line in file('debian/control'):
- line = line.strip()
- if line == '':
- section = None
- elif line.startswith('Source:'):
- section = 'Source'
- elif line.startswith('Package: ' + self.name):
- section = self.name
- elif line.startswith('XS-Python-Version:'):
- if section != 'Source':
- raise PyCentralError, \
- 'attribute XS-Python-Version not in Source section'
- self.sversion_field = line.split(':', 1)[1].strip()
- elif line.startswith('XB-Python-Version:'):
- if section == self.name:
- self.version_field = line.split(':', 1)[1].strip()
- except:
- pass
- if self.version_field == None:
- raise PyCentralVersionMissingError, \
- 'missing XB-Python-Version attribute in package %s' % self.name
- if self.sversion_field == None:
- raise PyCentralError, 'missing XS-Python-Version attribute'
- if self.parse_versions:
- self.sversion_info = pyversions.parse_versions(self.sversion_field)
- else:
- self.sversion_info = 'all' # dummy
- self.has_private_extension = self.sversion_info == 'current_ext'
-
- def move_files(self):
- """move files from the installation directory to the pycentral location"""
- import shutil
-
- dsttop = self.pkgdir + shared_base2
- try:
- os.makedirs(dsttop)
- except OSError:
- pass
- pversions = pyversions.supported_versions() \
- + pyversions.unsupported_versions() + pyversions.old_versions()
- pversions = list(set(pversions))
-
- # rename .egg-info files and dirs, remove *.py[co] files
- rename = 'norename' not in os.environ.get('DH_PYCENTRAL', '')
- vrx = re.compile(r'(.*)(-py\d\.\d)(.*)(\.egg-info|\.pth)$')
- for pversion in pversions:
- if pversion in ('python2.3', 'python2.4', 'python2.5'):
- srctop = os.path.join(self.pkgdir, 'usr/lib', pversion, 'site-packages')
- else:
- # srctop and srctop3 are the old/wrong locations, move these.
- srctop = os.path.join(self.pkgdir, 'usr/lib', pversion, 'site-packages')
- srctop2 = os.path.join(self.pkgdir, 'usr/lib', pversion, 'dist-packages')
- srctop3 = os.path.join(self.pkgdir, 'usr/local/lib', pversion, 'dist-packages')
- if os.path.isdir(srctop2) and (os.path.isdir(srctop) or os.path.isdir(srctop3)):
- raise PyCentralError, 'both directories site-packages and dist-packages exist.'
- if os.path.isdir(srctop):
- print 'renaming %s to %s' % (srctop, srctop2)
- os.rename(srctop, srctop2)
- elif os.path.isdir(srctop3):
- print 'renaming %s to %s' % (srctop3, srctop2)
- try:
- os.makedirs(os.path.dirname(srctop2))
- except OSError:
- pass
- os.rename(srctop3, srctop2)
- while srctop3:
- srctop3 = os.path.dirname(srctop3)
- try:
- os.rmdir(srctop3)
- except OSError:
- break
- srctop = srctop2
- # do the same with -dbg packages (which don't have an Python-Version attribute)
- pkgdbgdir = self.pkgdir + '-dbg'
- if os.path.isdir(pkgdbgdir):
- srcdtop = os.path.join(pkgdbgdir, 'usr/lib', pversion, 'site-packages')
- srcdtop2 = os.path.join(pkgdbgdir, 'usr/lib', pversion, 'dist-packages')
- srcdtop3 = os.path.join(pkgdbgdir, 'usr/local/lib', pversion, 'dist-packages')
- if os.path.isdir(srcdtop2) and (os.path.isdir(srcdtop) or os.path.isdir(srcdtop3)):
- print 'both directories site-packages and dist-packages exist.'
- if os.path.isdir(srcdtop):
- print 'renaming %s to %s' % (srcdtop, srcdtop2)
- os.rename(srcdtop, srcdtop2)
- elif os.path.isdir(srcdtop3):
- print 'renaming %s to %s' % (srcdtop3, srcdtop2)
- try:
- os.makedirs(os.path.dirname(srcdtop2))
- except OSError:
- pass
- os.rename(srcdtop3, srcdtop2)
- while srcdtop3:
- srcdtop3 = os.path.dirname(srcdtop3)
- try:
- os.rmdir(srcdtop3)
- except OSError:
- break
- srcdtop = os.path.join(pkgdbgdir, 'usr/lib/debug/usr/lib', pversion, 'site-packages')
- srcdtop2 = os.path.join(pkgdbgdir, 'usr/lib/debug/usr/lib', pversion, 'dist-packages')
- srcdtop3 = os.path.join(pkgdbgdir, 'usr/lib/debug/usr/local/lib', pversion, 'dist-packages')
- if os.path.isdir(srcdtop2) and (os.path.isdir(srcdtop) or os.path.isdir(srcdtop3)):
- print 'both directories site-packages and dist-packages exist.'
- if os.path.isdir(srcdtop):
- print 'renaming %s to %s' % (srcdtop, srcdtop2)
- os.rename(srcdtop, srcdtop2)
- elif os.path.isdir(srcdtop3):
- print 'renaming %s to %s' % (srcdtop3, srcdtop2)
- try:
- os.makedirs(os.path.dirname(srcdtop2))
- except OSError:
- pass
- os.rename(srcdtop3, srcdtop2)
- while srcdtop3:
- srcdtop3 = os.path.dirname(srcdtop3)
- try:
- os.rmdir(srcdtop3)
- except OSError:
- break
- for root, dirs, files in os.walk(srctop, topdown=False):
- for name in files:
- m = vrx.match(name)
- if m and rename:
- name2 = ''.join(m.group(1, 3, 4))
- print "rename: %s -> %s" % (name, name2)
- os.rename(os.path.join(root, name), os.path.join (root, name2))
- elif name.endswith('.pyc') or name.endswith('.pyo'):
- os.unlink(os.path.join(root, name))
- for name in dirs:
- m = vrx.match(name)
- if m and rename:
- name2 = ''.join(m.group(1, 3, 4))
- print "rename: %s -> %s" % (name, name2)
- os.rename(os.path.join(root, name), os.path.join (root, name2))
-
- # search for differences
- import filecmp
- class MyDircmp(filecmp.dircmp):
- def report(self):
- if self.left_only or self.right_only or self.diff_files or self.funny_files:
- self.differs = True
- print 'diff', self.left, self.right
- if self.left_only:
- self.left_only.sort()
- print 'Only in', self.left, ':', self.left_only
- if self.right_only:
- self.right_only.sort()
- print 'Only in', self.right, ':', self.right_only
- if self.diff_files:
- self.diff_files.sort()
- print 'Differing files :', self.diff_files
- if self.funny_files:
- self.funny_files.sort()
- print 'Trouble with common files :', self.funny_files
-
- for pv1 in pversions:
- for pv2 in pversions[pversions.index(pv1)+1:]:
- site1 = os.path.join(self.pkgdir, third_party_dir(pv1))
- site2 = os.path.join(self.pkgdir, third_party_dir(pv2))
- if not (os.path.isdir(site1) and os.path.isdir(site2)):
- continue
- dco = MyDircmp(site1, site2)
- dco.differs = False
- dco.report_full_closure()
-
- # move around
- for pversion in pversions:
- srctop = os.path.join(self.pkgdir, third_party_dir(pversion))
- for root, dirs, files in os.walk(srctop):
- if root == srctop:
- d = '.'
- else:
- d = root[len(srctop)+1:]
- for name in dirs:
- src = os.path.join(root, name)
- dst = os.path.join(dsttop, d, name)
- try:
- os.mkdir(dst)
- shutil.copymode(src, dst)
- except OSError:
- pass
- for name in files:
- src = os.path.join(root, name)
- dst = os.path.join(dsttop, d, name)
- if re.search(r'\.so(\.\d+)*?$', name):
- continue
- # TODO: if dst already exists, make sure, src == dst
- os.rename(src, dst)
- # remove empty dirs in /usr/lib/pythonX.Y
- for root, dirs, files in os.walk(self.pkgdir + '/usr/lib', topdown=False):
- try:
- if re.match("/usr/lib/python\d\.\d($|/)", root.replace(self.pkgdir, "")):
- os.rmdir(root)
- except OSError:
- pass
- try:
- os.rmdir(self.pkgdir + '/usr/lib')
- except OSError:
- pass
- # remove empty dirs in /usr/share/pyshared
- for root, dirs, files in os.walk(self.pkgdir + shared_base2, topdown=False):
- try:
- os.rmdir(root)
- except OSError:
- pass
- try:
- os.rmdir(self.pkgdir + shared_base2)
- except OSError:
- pass
-
- def add_shared_links(self):
- versions = pyversions.requested_versions(self.sversion_field, True)
- tgttop = os.path.join(self.pkgdir, shared_base2.strip('/'))
- existing_links = []
- for version in versions:
- linktop = os.path.join(self.pkgdir, third_party_dir(version))
- try:
- os.makedirs(linktop)
- except OSError:
- pass
- for root, dirs, files in os.walk(tgttop, topdown=True):
- linkroot = root.replace(tgttop, linktop, 1)
- for name in files:
- tgt = os.path.join(root, name)
- link = os.path.join(linkroot, name)
- if os.path.exists(link):
- existing_links.append(link)
- else:
- rel_tgt = build_relative_link(tgt, link)
- os.symlink(rel_tgt, link)
- for name in dirs:
- try:
- os.makedirs(os.path.join(linkroot, name))
- except OSError:
- pass
- if existing_links:
- print 'Found existing files while including symlinks:'
- for link in existing_links:
- print ' ', link
- raise PyCentralError, 'Found existing files while including symlinks'
-
- def gen_substvars(self):
- supported = [d[6:] for d in pyversions.supported_versions()
- if re.match(r'python\d\.\d', d)]
- versions = ''
- prversions = ''
- self.depends = None
- if len(self.has_shared_module) or len(self.has_shared_extension):
- # shared modules / extensions
- if len(self.has_shared_extension):
- versions = self.has_shared_extension.keys()
- else:
- if self.sversion_info in ('current', 'current_ext'):
- versions = 'current'
- elif self.sversion_info == 'all':
- versions = 'all'
- prversions = supported
- else:
- versions = self.sversion_field
- prversions = list(self.sversion_info.intersection(supported))
- self.depends = version2depends(self.sversion_info)
- elif self.has_private_module or self.has_private_extension:
- if self.sversion_info == 'all':
- versions = 'current'
- elif self.sversion_info == 'current':
- versions = 'current'
- elif self.sversion_info == 'current_ext':
- versions = [pyversions.default_version(version_only=True)]
- elif isinstance(self.sversion_info, list) or isinstance(self.sversion_info, set):
- # exact version info required, no enumeration, no relops
- if len(self.sversion_info) != 1 or not re.match(r'\d\.\d', self.sversion_info[0]):
- raise PyCentralError, 'no exact version for package with private modules'
- versions = [list(self.sversion_info)[0]]
- else:
- raise PyCentralError, 'version error for package with private modules'
- else:
- # just "copy" it from the source field
- if self.sversion_info == 'current':
- versions = 'current'
- elif self.sversion_info == 'current_ext':
- versions = [pyversions.default_version(version_only=True)]
- elif self.sversion_info == 'all':
- versions = 'all'
- prversions = supported
- else:
- versions = self.sversion_field
- prversions = list(self.sversion_info.intersection(supported))
- self.depends = version2depends(self.sversion_info)
-
- if (len(self.has_shared_module) or len(self.has_shared_extension)) \
- and self.has_private_module or self.has_private_extension:
- # use case? use the information for the shared stuff
- pass
- if versions == '':
- raise PyCentralError, 'unable to determine Python-Version attribute'
- if isinstance(versions, list) or isinstance(versions, set):
- self.version_field = ', '.join(versions)
- else:
- self.version_field = versions
- if not self.depends:
- self.depends = version2depends(versions)
- if self.name.startswith('python-'):
- if prversions == '':
- prversions = versions
- self.provides = ', '.join([self.name.replace('python-', 'python%s-' % ver)
- for ver in prversions])
-
- def set_version_field(self, version_field):
- self.version_field = version_field
- if self.parse_versions:
- self.version_info = pyversions.parse_versions(version_field)
-
- def read_version_info(self, use_default_if_missing=False):
- """Read the Python-Version information field"""
- if self.version_field:
- return
- if self.pkgconfig and self.pkgconfig.has_option('python-package', 'python-version'):
- self.version_field = self.pkgconfig.get('python-package', 'python-version')
- logging.debug("Using python-version from pkgconfig: %s" % self.version_field)
- elif os.environ.has_key("PYCENTRAL_NO_DPKG_QUERY"):
- logging.debug("Not using dpkg-query as requested")
- needle = "Package: %s\n" % self.name
- for block in open("/var/lib/dpkg/status").read().split("\n\n"):
- if needle in block:
- for line in block.split("\n"):
- if line.startswith('Python-Version:'):
- self.version_field = line.split(':', 1)[1].strip()
- break
- else:
- logging.debug("dpkg-query -s %s" % self.name)
- cmd = ['/usr/bin/dpkg-query', '-s', self.name]
- try:
- import subprocess
- p = subprocess.Popen(cmd, bufsize=1,
- shell=False, stdout=subprocess.PIPE)
- fd = p.stdout
- except ImportError:
- fd = os.popen(' '.join(cmd))
-
- for line in fd:
- if line.startswith('Python-Version:'):
- self.version_field = line.split(':', 1)[1].strip()
- break
- fd.close()
- # now verify/parse it
- if not self.version_field and use_default_if_missing:
- logging.warn("%s: has no Python-Version field, assuming default runtime" % self.name)
- self.version_field = get_default_runtime().version
- if not self.version_field:
-
- raise PyCentralError, "package has no field Python-Version"
- if self.parse_versions:
- self.version_info = pyversions.parse_versions(self.version_field)
-
- def set_default_runtime_from_version_info(self):
- versions = list(pyversions.requested_versions(self.version_field, version_only=True))
- if not versions:
- #raise PyCentralError, "no matching runtime for `%s'" % self.version_field
- logging.warn("%s: no matching runtime for `%s', using default"
- % (self.name, self.version_field))
- self.default_runtime = get_default_runtime()
- if len(versions) == 1:
- self.default_runtime = get_runtime_for_version(versions[0])
- elif pyversions.default_version(version_only=True) in versions:
- self.default_runtime = get_default_runtime()
- else:
- self.default_runtime = get_runtime_for_version(versions[0])
-
- def byte_compile(self, runtimes, bc_option, exclude_regex, ignore_errors=False):
- """byte compiles all files not handled by pycentral"""
-
- logging.debug(" byte-compile %s" % self.name)
- if self.shared_files:
- ppos = len(self.shared_prefix)
- for rt in runtimes:
- linked_files = [ rt.prefix + fn[ppos:]
- for fn in self.shared_files
- if fn[-3:] == '.py']
- rt.byte_compile(linked_files, bc_option, exclude_regex, ignore_errors)
-
- for pyver, files in self.pylib_files.items():
- logging.debug("bc for v%s (%d files)" % (pyver, len(files)))
- rt = get_runtime_for_version(pyver)
- if rt in runtimes:
- rt.byte_compile(files, bc_option, exclude_regex)
-
- if self.private_files:
- logging.debug("bc %s private (%d files)" %
- (self.default_runtime.version, len(self.private_files)))
- rt = self.default_runtime
- rt.byte_compile(self.private_files, bc_option, exclude_regex)
-
- def remove_bytecode(self):
- """remove all byte-compiled files not handled by pycentral"""
-
- assert self.oldstyle
-
- logging.debug(" remove byte-code for %s" % self.name)
- pyfiles = []
- for files in self.pylib_files.values():
- pyfiles.extend(files)
- pyfiles.extend(self.private_files)
-
- errors = False
- for ext in ('c', 'o'):
- for fn in pyfiles:
- fnc = fn + ext
- if os.path.exists(fnc):
- try:
- os.unlink(fnc)
- except OSError, e:
- print "Sorry", e
- errors = True
- if errors:
- raise PyCentralError
-
- def link_shared_files(self, rt):
- """link shared files at runtime"""
- #if samefs(rt.prefix, self.shared_files[0]):
- # link_cmd = os.link
- #else:
- # link_cmd = os.symlink
- logging.debug("\tlink shared files %s/%s" % (rt.name, self.name))
- if not self.shared_files:
- return []
- link_cmd = os.symlink
- ppos = len(self.shared_prefix)
- existing_files = []
- for fn in self.shared_files:
- fn2 = rt.prefix + fn[ppos:]
- if os.path.isdir(fn) and not os.path.islink(fn):
- continue
- if os.path.exists(fn2):
- link = abs_link = None
- if os.path.islink(fn2):
- link = abs_link = os.readlink(fn2)
- if link.startswith('../'):
- abs_link = os.path.normpath(os.path.join(os.path.dirname(fn2), link))
- if abs_link == fn or link == fn:
- continue
- if not link or not (abs_link.startswith(shared_base2) or abs_link.startswith(shared_base)):
- existing_files.append(fn2)
-
- if existing_files:
- conf = get_debian_config()
- overwrite_local = conf.get('DEFAULT', 'overwrite-local') == '1'
- if overwrite_local:
- print '\n '.join(["overwriting local files:"] + existing_files)
-
- linked_files = []
- try:
- for fn in self.shared_files:
- fn2 = rt.prefix + fn[ppos:]
- if os.path.isdir(fn) and not os.path.islink(fn):
- if os.path.isdir(fn2):
- continue
- os.makedirs(fn2)
- linked_files.append(fn2)
- else:
- if os.path.exists(fn2):
- msg = "already exists: %s" % fn2
- link = abs_link = None
- if os.path.islink(fn2):
- link = abs_link = os.readlink(fn2)
- if link.startswith('../'):
- abs_link = os.path.normpath(os.path.join(os.path.dirname(fn2), link))
- if abs_link == fn or link == fn:
- linked_files.append(fn2)
- continue
- if not link or not (abs_link.startswith(shared_base2) or abs_link.startswith(shared_base)):
- msg = msg + " -> %s" % link
- if overwrite_local:
- print "warning:", msg
- os.unlink(fn2)
- else:
- continue # raise PyCentralError, msg at end of method
- # make sure that fn2 really does not exist; this is a
- # special hack to make pycentral work with fakechroot,
- # which has a slightly weird treatment of symlinks
- # now needed to switch between old and new prefix
- try:
- os.unlink(fn2)
- except OSError:
- pass
- link_cmd(fn, fn2)
- linked_files.append(fn2)
- except PyCentralError, msg:
- raise
- except Exception, msg:
- print msg
- # FIXME: undo
- linked_files.reverse()
- return []
- else:
- if existing_files and not overwrite_local:
- s = get_file_overwrite_error(existing_files)
- raise PyCentralError, s
- return linked_files
-
- def unlink_shared_files(self, rt):
- logging.debug('\tunlink_shared_files %s/%s' % (rt.name, self.name))
- if not self.shared_files:
- return
- ppos = len(self.shared_prefix)
- shared_files = self.shared_files[:]
- shared_files.reverse()
- for fn in shared_files:
- fn2 = rt.prefix + fn[ppos:]
- if os.path.isdir(fn2) and not os.path.islink(fn2):
- try:
- os.removedirs(fn2)
- except OSError:
- pass
- else:
- if os.path.exists(fn2):
- os.unlink(fn2)
-
- def list_shared_files(self, rt):
- logging.debug('\tlist_shared_files %s/%s' % (rt.name, self.name))
- if not self.shared_files:
- return
- ppos = len(self.shared_prefix)
- for fn in self.shared_files:
- fn2 = rt.prefix + fn[ppos:]
- yield fn2
-
-
- def install(self, runtimes, bc_option, exclude_regex,
- byte_compile_default=True, ignore_errors=False):
- logging.debug('\tinstall package %s' % self.name)
- # install shared .py files
- symlinks_included = self.pkgconfig.getboolean('pycentral', 'include-links')
- if symlinks_included:
- pass
- else:
- if self.shared_files:
- for rt in runtimes:
- linked_files = self.link_shared_files(rt)
- rt.byte_compile(linked_files, bc_option, exclude_regex, ignore_errors)
- # byte compile files inside prefix
- if self.pylib_files:
- for pyver, files in self.pylib_files.items():
- rt = get_runtime_for_version(pyver)
- if rt in runtimes:
- rt.byte_compile(files, bc_option, exclude_regex, ignore_errors)
- # byte compile with the default runtime for the package
- if byte_compile_default:
- if self.private_files:
- self.default_runtime.byte_compile(self.private_files, bc_option,
- exclude_regex, ignore_errors)
-
- def prepare(self, runtimes, old_runtimes, old_pkg, ignore_errors=False):
- logging.debug('\tprepare package %s' % self.name)
-
- if old_pkg and old_pkg.private_files:
- fs_in_old = set([fn for fn in old_pkg.private_files if fn[-3:] == '.py'])
- fs_in_new = set([fn for fn in self.private_files if fn[-3:] == '.py'])
- removed_fs = list(fs_in_old.difference(fs_in_new))
- if removed_fs:
- logging.debug_list('\t', 'removed private', removed_fs)
- default_runtime.remove_byte_code(removed_fs)
-
- old_pylib_fs = []
- if old_pkg and old_pkg.pylib_files:
- for pyver, files in old_pkg.pylib_files.items():
- fs_in_old = set([fn for fn in files if fn[-3:] == '.py'])
- fs_in_new = set([fn for fn in self.pylib_files.get(pyver, []) if fn[-3:] == '.py'])
- removed_fs = list(fs_in_old.difference(fs_in_new))
- if removed_fs:
- logging.debug_list('\t', 'removed pylib', removed_fs)
- default_runtime.remove_byte_code(removed_fs)
- old_pylib_fs += files
- old_pylib_fs += old_pkg.other_pylib_files
-
- if old_pkg and old_pkg.shared_files:
- for rt in old_runtimes:
- if rt in runtimes:
- continue
- linked_files = [ rt.prefix + fn[ppos:]
- for fn in old_pkg.shared_files if fn[-3:] == '.py']
- if linked_files:
- logging.debug_list('\t', 'removed runtimes', linked_files)
- default_runtime.remove_byte_code(linked_files)
- self.unlink_files(rt)
-
- if not self.shared_files:
- return
-
- dirs_in_new = set([fn for fn, t in self.pkgconfig.items('files')
- if t == 'd' if fn.startswith(self.shared_prefix)])
- dirs_in_old = set()
- if old_pkg:
- dirs_in_old = set([fn for fn, t in old_pkg.pkgconfig.items('files')
- if t == 'd' if fn.startswith(self.shared_prefix)])
- new_dirs = list(dirs_in_new.difference(dirs_in_old))
- new_dirs.sort()
- removed_dirs = list(dirs_in_old.difference(dirs_in_new))
- removed_dirs.sort()
-
- fs_in_new = set([fn for fn, t in self.pkgconfig.items('files')
- if t == 'f' if fn.startswith(self.shared_prefix)])
- fs_in_old = set()
- if old_pkg:
- fs_in_old = set([fn for fn, t in old_pkg.pkgconfig.items('files')
- if t == 'f' if fn.startswith(self.shared_prefix)])
- new_fs = list(fs_in_new.difference(fs_in_old))
- new_fs.sort()
- removed_fs = list(fs_in_old.difference(fs_in_new))
- removed_fs.sort()
-
- logging.debug_list('\t', 'new dirs', new_dirs)
- logging.debug_list('\t', 'removed dirs', removed_dirs)
- logging.debug_list('\t', 'new files', new_fs)
- logging.debug_list('\t', 'removed files', removed_fs)
-
- link_cmd = os.symlink
- ppos = len(self.shared_prefix)
- existing_files = []
- for rt in runtimes:
- for f1 in new_fs:
- f2 = rt.prefix + f1[ppos:]
- if os.path.exists(f2):
- link = abs_link = None
- if os.path.islink(f2):
- link = abs_link = os.readlink(f2)
- if link.startswith('../'):
- abs_link = os.path.normpath(os.path.join(os.path.dirname(f2), link))
- if abs_link == f1 or link == f1:
- continue
- if not link or not (abs_link.startswith(shared_base2) or abs_link.startswith(shared_base)):
- existing_files.append(f2)
- if existing_files:
- # if the current installed version does not use python-central
- # then having a file here is expected and harmless
- if not self.name in [p for (p,v) in read_dpkg_status()]:
- logging.info("%s: upgrade from package version not using python-central" % self.name)
- return
- # if all existing files are found in the old package in
- # /usr/lib/pythonX.Y/site-packages, and moved to the shared area,
- # do nothing.
- not_in_same_pkg = set(existing_files)
- if old_pkg:
- not_in_same_pkg.difference_update(old_pylib_fs)
- if not_in_same_pkg == set():
- logging.info("%s: upgrade from package version with unmoved files" % self.name)
- return
- conf = get_debian_config()
- overwrite_local = conf.get('DEFAULT', 'overwrite-local') == '1'
- if overwrite_local:
- print "overwriting local files"
-
- for rt in runtimes:
- for d1 in new_dirs:
- d2 = rt.prefix + d1[ppos:]
- if os.path.isdir(d2):
- continue
- os.makedirs(d2)
- for f1 in new_fs:
- f2 = rt.prefix + f1[ppos:]
- if os.path.exists(f2):
- msg = "already exists: %s" % f2
- link = abs_link = None
- if os.path.islink(f2):
- link = abs_link = os.readlink(f2)
- if link.startswith('../'):
- abs_link = os.path.normpath(os.path.join(os.path.dirname(f2), link))
- if abs_link == f1 or link == f1:
- continue
- if not link or not (abs_link.startswith(shared_base2) or abs_link.startswith(shared_base)):
- msg = msg + " -> %s" % link
- if overwrite_local:
- print "warning:", msg
- os.unlink(f2)
- else:
- continue # raise PyCentralError, msg at end of loop
- # hack to make pycentral work with fakechroot
- # now needed to switch between old and new prefix
- try:
- os.unlink(f2)
- except OSError:
- pass
- try:
- d = os.path.dirname(f2)
- if not os.path.isdir(d):
- print "create directory %s" % d
- os.makedirs(d)
- link_cmd(f1, f2)
- except OSError:
- print "unable to create symlink %s" % f2
- raise
- if existing_files and not overwrite_local:
- raise PyCentralError, "not overwriting local files"
-
- for rt in runtimes:
- for f1 in removed_fs:
- f2 = rt.prefix + f1[ppos:]
- try:
- os.unlink(f2)
- os.unlink(f2 + 'c')
- os.unlink(f2 + 'o')
- except OSError:
- pass
- for d1 in removed_dirs:
- d2 = rt.prefix + d1[ppos:]
- try:
- os.rmdir(d2)
- except OSError:
- pass
-
- return
-
- def remove(self, runtimes, remove_script_files=True):
- logging.debug('\tremove package %s' % self.name)
- # remove shared .py files
- symlinks_included = self.pkgconfig.getboolean('pycentral', 'include-links')
- if symlinks_included:
- pass
- else:
- if self.shared_files:
- ppos = len(self.shared_prefix)
- for rt in runtimes:
- linked_files = [ rt.prefix + fn[ppos:]
- for fn in self.shared_files
- if fn[-3:] == '.py']
- #print self.shared_files
- #print linked_files
- default_runtime.remove_byte_code(linked_files)
- self.unlink_shared_files(rt)
- # remove byte compiled files inside prefix
- if self.pylib_files:
- for pyver, files in self.pylib_files.items():
- rt = get_runtime_for_version(pyver)
- if rt in runtimes:
- default_runtime.remove_byte_code(files)
- # remove byte code for script files
- if remove_script_files:
- if self.private_files:
- default_runtime.remove_byte_code(self.private_files)
-
- def list(self, runtimes, list_script_files=True):
- logging.debug('\tlist package %s' % self.name)
- # list shared .py files
- symlinks_included = self.pkgconfig.getboolean('pycentral', 'include-links')
- if not symlinks_included and self.shared_files:
- ppos = len(self.shared_prefix)
- for rt in runtimes:
- linked_files = [ rt.prefix + fn[ppos:]
- for fn in self.shared_files
- if fn[-3:] == '.py']
- for f in default_runtime.list_byte_code(linked_files):
- yield f
- for f in self.list_shared_files(rt):
- yield f
- # list byte compiled files inside prefix
- if self.pylib_files:
- for pyver, files in self.pylib_files.items():
- rt = get_runtime_for_version(pyver)
- if rt in runtimes:
- for f in default_runtime.list_byte_code(files):
- yield f
- # list byte code for script files
- if list_script_files:
- if self.private_files:
- for f in default_runtime.list_byte_code(self.private_files):
- yield f
-
- def update_bytecode_files(self, runtimes, rt_default, bc_option):
- # byte-compile with default python version
- logging.debug('\tupdate byte-code for %s' % self.name)
- exclude_regex = None
- # update shared .py files
- if self.shared_files:
- ppos = len(self.shared_prefix)
- for rt in runtimes:
- if rt == rt_default:
- linked_files = self.link_shared_files(rt)
- rt.byte_compile(linked_files, bc_option, exclude_regex)
- else:
- linked_files = [ rt.prefix + fn[ppos:]
- for fn in self.shared_files
- if fn[-3:] == '.py']
- rt.remove_byte_code(linked_files)
- self.unlink_shared_files(rt)
- # byte compile with the default runtime for the package
- if self.private_files:
- self.default_runtime.byte_compile(self.private_files,
- bc_option, exclude_regex, force=True)
-
- known_actions = {}
- def register_action(action_class):
- known_actions[action_class.name] = action_class
-
- class Action:
- _option_parser = None
- name = None
- help = ""
- usage = "<options>"
- def __init__(self):
- self.errors_occured = 0
- parser = self.get_option_parser()
- parser.set_usage(
- 'usage: %s [<options> ...] %s %s' % (program, self.name, self.usage))
-
- def get_option_parser(self):
- if not self._option_parser:
- p = OptionParser()
- self._option_parser = p
- return self._option_parser
-
- def info(self, msg, stream=sys.stderr):
- logging.info('%s %s: %s' % (program, self.name, msg))
-
- def warn(self, msg, stream=sys.stderr):
- logging.warn('%s %s: %s' % (program, self.name, msg))
-
- def error(self, msg, stream=sys.stderr, go_on=False):
- logging.error('%s %s: %s' % (program, self.name, msg))
- self.errors_occured += 1
- if not go_on:
- sys.exit(1)
-
- def parse_args(self, arguments):
- self.options, self.args = self._option_parser.parse_args(arguments)
- return self.options, self.args
-
- def check_args(self, global_options):
- return self.errors_occured
-
- def run(self, global_opts):
- pass
-
-
- class ActionByteCompile(Action):
- """byte compile the *.py files in <package> using the the
- default python version (or use the version specified with -v.
- Any additional directory arguments are ignored (only files
- found in the package are byte compiled. Files in
- /usr/lib/pythonX.Y are compiled with the matching python version.
-
- bccompile is a replacement for the current byte compilation
- generated by the dh_python debhelper script.
- """
- name = 'bccompile'
- help = 'byte compile .py files in a package'
- usage = '[<options>] <package> [<dir> ...]'
-
- def get_option_parser(self):
- if not self._option_parser:
- p = OptionParser()
- p.add_option('-x', '--exclude',
- help="skip files matching the regular expression",
- default=None, action='store', dest='exclude')
- p.add_option('-V', '--version',
- help="byte compile using this python version",
- default='current', action='store', dest='version')
- self._option_parser = p
- return self._option_parser
-
- def check_args(self, global_options):
- if len(self.args) < 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.pkgname = self.args[0]
- self.runtime = get_runtime_for_version(self.options.version)
- if not self.runtime:
- self.error("unknown runtime version %s" % self.options.version)
-
- if not os.path.exists('/var/lib/dpkg/info/%s.list' % self.pkgname):
- self.error("package %s is not installed" % self.pkgname)
- self.pkg = DebPackage('package', self.pkgname, oldstyle=False,
- default_runtime=self.runtime)
- self.pkg.read_version_info()
- return self.errors_occured
-
- def run(self, global_options):
- logging.debug('bccompile %s' % self.pkgname)
- runtimes = get_installed_runtimes()
- config = get_debian_config()
- bc_option = config.get('DEFAULT', 'byte-compile')
- requested = pyversions.requested_versions_for_runtime(self.pkg.version_field, version_only=True)
- used_runtimes = [rt for rt in runtimes if rt.short_name in requested]
- # called with directories as arguments
- if 0 and self.directories:
- try:
- for version, dirs in self.pylib_dirs.items():
- rt = get_runtime_for_version(version)
- rt.byte_compile_dirs(dirs, bc_option, self.options.exclude)
- if self.private_dirs:
- version = pkg.version_field
- if version == 'current':
- version = pyversions.default_version(version_only=True)
- rt = get_runtime_for_version(version)
- rt.byte_compile_dirs(private_dirs, bc_option, self.options.exclude)
- except PyCentralError:
- self.error("error byte-compiling package `%s'" % self.pkgname)
- return
-
- try:
- self.pkg.byte_compile(used_runtimes, bc_option, self.options.exclude)
- except PyCentralError:
- self.error("error byte-compiling package `%s'" % self.pkgname)
-
- register_action(ActionByteCompile)
-
- class ActionPkgInstall(Action):
- name = 'pkginstall'
- help = 'make a package available for all supported runtimes'
- usage = '[<options>] <package>'
-
- def get_option_parser(self):
- if not self._option_parser:
- p = OptionParser()
- p.add_option('-x', '--exclude',
- help="skip files matching the regular expression",
- default=None, action='store', dest='exclude')
- self._option_parser = p
- return self._option_parser
-
- def check_args(self, global_options):
- if len(self.args) != 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.pkgname = self.args[0]
- if not os.path.exists('/var/lib/dpkg/info/%s.list' % self.pkgname):
- self.error("package %s is not installed" % self.pkgname)
- return self.errors_occured
-
- def run(self, global_options):
- runtimes = get_installed_runtimes()
- config = get_debian_config()
- bc_option = config.get('DEFAULT', 'byte-compile')
- pkg = DebPackage('package', self.args[0], oldstyle=False)
- pkg.read_version_info()
- requested = pyversions.requested_versions_for_runtime(pkg.version_field, version_only=True)
- used_runtimes = [rt for rt in runtimes if rt.short_name in requested]
- try:
- pkg.set_default_runtime_from_version_info()
- except ValueError:
- # Package doesn't provide support for any supported runtime
- if len(used_runtimes) == 0:
- self.error('%s needs unavailable runtime (%s)'
- % (self.pkgname, pkg.version_field))
- else:
- # Still byte compile for the available runtimes (with the
- # first matching runtime)
- pkg.default_runtime = get_runtime_for_version(used_runtimes[0])
- logging.debug('\tavail=%s, pkg=%s, install=%s'
- % ([rt.short_name for rt in runtimes],
- pkg.version_field,
- [rt.short_name for rt in used_runtimes]))
- try:
- pkg.install(used_runtimes, bc_option,
- self.options.exclude, byte_compile_default=True)
- except PyCentralError, msg:
- self.error(msg)
-
-
- register_action(ActionPkgInstall)
-
-
- class ActionPkgPrepare(Action):
- name = 'pkgprepare'
- help = 'prepare a package for all supported runtimes'
- usage = '[<options>] <package>'
-
- def get_option_parser(self):
- if not self._option_parser:
- p = OptionParser()
- p.add_option('-x', '--exclude',
- help="skip files matching the regular expression",
- default=None, action='store', dest='exclude')
- self._option_parser = p
- return self._option_parser
-
- def check_args(self, global_options):
- if len(self.args) != 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.pkgname = self.args[0]
- # FIXME: run from the preinst, package may not exist
- #if not os.path.exists('/var/lib/dpkg/info/%s.list' % self.pkgname):
- # self.error("package %s is not installed" % self.pkgname)
- return self.errors_occured
-
- def run(self, global_options):
- # functionality disabled starting with 0.6.9
- return
-
- runtimes = get_installed_runtimes()
- config = get_debian_config()
- pkgconfig = PyCentralConfigParser()
- pkgconfig.optionxform = str
- pkgconfig.readfp(sys.stdin)
- version_field = pkgconfig.get('python-package', 'python-version')
- try:
- requested = pyversions.requested_versions_for_runtime(version_field, version_only=True)
- except pyversions.PyCentralEmptyValueError, msg:
- # cannot install yet; remove the symlinked files and byte code files from the old
- # version, rely on the pkginstall in the postinst.
- print "pycentral: required runtimes not yet installed, skip pkgprepare, call pkgremove"
- runtimes = get_installed_runtimes(with_unsupported=True)
- pkg = DebPackage('package', self.args[0], oldstyle=False)
- pkg.read_version_info()
- pkg.default_runtime = get_default_runtime()
- try:
- pkg.remove(runtimes, remove_script_files=True)
- except PyCentralError, msg:
- self.warn(msg)
- return
- used_runtimes = [rt for rt in runtimes if rt.short_name in requested]
- pkg = DebPackage('package', self.args[0], oldstyle=False, pkgconfig=pkgconfig)
- pkg.set_version_field(version_field)
- try:
- pkg.set_default_runtime_from_version_info()
- except ValueError:
- # Package doesn't provide support for any supported runtime
- if len(used_runtimes) == 0:
- self.error('%s needs unavailable runtime (%s)'
- % (self.pkgname, pkg.version_field))
- else:
- # Still byte compile for the available runtimes (with the
- # first matching runtime)
- pkg.default_runtime = get_runtime_for_version(used_runtimes[0])
-
- if os.path.exists('/var/lib/dpkg/info/%s.list' % self.pkgname):
- old_pkg = DebPackage('package', self.args[0], oldstyle=False)
- try:
- old_pkg.read_version_info()
- except PyCentralError:
- old_pkg.set_version_field(version_field)
-
- old_requested = pyversions.requested_versions_for_runtime(old_pkg.version_field, version_only=True)
- old_used_runtimes = [rt for rt in runtimes if rt.short_name in requested]
- else:
- old_pkg = None
- old_used_runtimes = []
- logging.debug('\tavail=%s, pkg=%s, prepare=%s'
- % ([rt.short_name for rt in runtimes],
- version_field,
- [rt.short_name for rt in used_runtimes]))
- try:
- pkg.prepare(used_runtimes, old_used_runtimes, old_pkg)
- except PyCentralError, msg:
- self.error(msg)
-
- register_action(ActionPkgPrepare)
-
-
- class ActionBCRemove(Action):
- """remove the byte-compiled files in <package>.
-
- bccompile is a replacement for the current byte compilation
- generated by the dh_python debhelper script.
- """
- name = 'bcremove'
- help = 'remove the byte compiled .py files'
- usage = '<package>'
-
- def check_args(self, global_options):
- if len(self.args) != 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.pkgname = self.args[0]
- if not os.path.exists('/var/lib/dpkg/info/%s.list' % self.pkgname):
- self.error("package %s is not installed" % self.pkgname)
- return self.errors_occured
-
- def run(self, global_options):
- pkg = DebPackage('package', self.args[0], oldstyle=True)
- try:
- pkg.remove_bytecode()
- except PyCentralError, msg:
- self.error(msg)
-
- register_action(ActionBCRemove)
-
-
- class ActionPkgRemove(Action):
- """
- """
- name = 'pkgremove'
- help = 'remove a package installed for all supported runtimes'
- usage = '<package>'
-
- def check_args(self, global_options):
- if len(self.args) != 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.pkgname = self.args[0]
- if not os.path.exists('/var/lib/dpkg/info/%s.list' % self.pkgname):
- self.error("package %s is not installed" % self.pkgname)
- return self.errors_occured
-
- def run(self, global_options):
- runtimes = get_installed_runtimes(with_unsupported=True)
- pkg = DebPackage('package', self.args[0], oldstyle=False)
- pkg.read_version_info(use_default_if_missing=True)
- try:
- pkg.set_default_runtime_from_version_info()
- except ValueError:
- # original runtime is already removed, use the default for removal
- pkg.default_runtime = get_default_runtime()
- try:
- pkg.remove(runtimes, remove_script_files=True)
- except PyCentralError, msg:
- self.error(msg)
-
- register_action(ActionPkgRemove)
-
- class ActionPkgList(Action):
- name = 'pkglist'
- help = 'list all pycentral-managed files for <package>'
- usage = '<package>'
-
- def check_args(self, global_options):
- if len(self.args) != 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.pkgname = self.args[0]
- if not os.path.exists('/var/lib/dpkg/info/%s.list' % self.pkgname):
- self.error("package %s is not installed" % self.pkgname)
- return self.errors_occured
-
- def run(self, global_options):
- runtimes = get_installed_runtimes(with_unsupported=True)
- pkg = DebPackage('package', self.args[0], oldstyle=False)
- pkg.read_version_info()
- try:
- pkg.set_default_runtime_from_version_info()
- except ValueError:
- # original runtime may be removed, use the default
- pkg.default_runtime = get_default_runtime()
- try:
- for f in pkg.list(runtimes, list_script_files=True):
- print f
- except PyCentralError, msg:
- self.error(msg)
-
- register_action(ActionPkgList)
-
-
- class ActionRuntimeInstall(Action):
- name = 'rtinstall'
- help = 'make installed packages available for this runtime'
-
- def get_option_parser(self):
- if not self._option_parser:
- p = OptionParser()
- p.add_option('-i', '--ignore-errors',
- help="ignore errors during byte compilations",
- default=None, action='store', dest='ignore')
- self._option_parser = p
- return self._option_parser
-
- def check_args(self, global_options):
- if len(self.args) != 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.rtname = self.args[0]
- if self.rtname[-8:] == '-minimal':
- self.rtname = self.rtname[:-8]
- self.runtime = None
- for rt in get_installed_runtimes():
- if rt.name == self.rtname:
- self.runtime = rt
- break
- if not self.runtime:
- self.error('installed runtime %s not found' % self.rtname)
- self.rtname_short = self.rtname[6:]
- return self.errors_occured
-
- def run(self, global_options):
- packages = [(p, v) for p, v in read_dpkg_status()
- if not p in (self.rtname, self.rtname+'-minimal')]
- needed_packages = []
- for pkgname, vstring in packages:
- try:
- requested = list(pyversions.requested_versions(vstring, version_only=True))
- if not self.rtname_short in requested:
- logging.info("%s not in what requested_versions() returned, adding it anyway" % self.rtname_short)
- requested.append(self.rtname_short)
- except ValueError:
- logging.info('\tunsupported for %s: %s (%s)' % (self.rtname, pkgname, vstring))
- continue
- if self.runtime.short_name in requested:
- needed_packages.append((pkgname, vstring, requested))
- logging.info('\t%d packages with Python-Version info installed, %d for %s'
- % (len(packages), len(needed_packages), self.rtname))
-
- # XXX not needed for an upgrade of a runtime
- byte_compile_for_default = (self.runtime == default_runtime)
-
- bc_option = get_debian_config().get('DEFAULT', 'byte-compile')
- for pkgname, vstring, vinfo in needed_packages:
- try:
- logging.info('\tsupport %s for %s' % (pkgname, self.rtname))
- pkg = DebPackage('package', pkgname, oldstyle=False)
- pkg.read_version_info()
- try:
- pkg.set_default_runtime_from_version_info()
- except ValueError:
- logging.warn('\t%s not available for %s (%s)'
- % (pkgname, self.rtname, pkg.version_field))
- pkg.install([self.runtime], bc_option, None,
- byte_compile_for_default,
- ignore_errors = self.options.ignore != None)
- except PyCentralError, msg:
- self.error('package %s: %s' % (pkgname, msg))
-
- register_action(ActionRuntimeInstall)
-
- class ActionRuntimeRemove(Action):
- name = 'rtremove'
- help = 'remove packages installed for this runtime'
-
- def check_args(self, global_options):
- if len(self.args) != 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.rtname = self.args[0]
- if self.rtname[-8:] == '-minimal':
- self.rtname = self.rtname[:-8]
- self.runtime = None
- for rt in get_installed_runtimes(with_unsupported=True):
- if rt.name == self.rtname:
- self.runtime = rt
- break
- if not self.runtime:
- self.error('installed runtime %s not found' % self.rtname)
- return self.errors_occured
-
- def run(self, global_options):
- packages = [(p, v) for p, v in read_dpkg_status(verbose=True)
- if not p in (self.rtname, self.rtname+'-minimal')]
- needed_packages = []
- import subprocess
- for pkgname, vstring in packages:
- if not os.path.exists('/var/lib/dpkg/info/%s.list' % pkgname):
- # already removed, but /var/lib/dpkg/status not yet updated
- continue
- cmd = ['/usr/bin/dpkg-query', '-W', '-f', '${Status}\n', pkgname]
- p = subprocess.Popen(cmd, bufsize=1,
- shell=False, stdout=subprocess.PIPE)
- fd = p.stdout
- status = fd.readline().strip().split()
- fd.close()
- if not 'installed' in status:
- # already removed, but /var/lib/dpkg/status not yet updated
- continue
- try:
- requested = list(pyversions.requested_versions_for_runtime(vstring, version_only=True))
- except ValueError:
- logging.info('\tunsupported for %s: %s (%s)' % (self.rtname, pkgname, vstring))
- continue
- if self.runtime.short_name in requested:
- needed_packages.append((pkgname, vstring, requested))
- logging.info('\t%d pycentral supported packages installed, %d for %s'
- % (len(packages), len(needed_packages), self.rtname))
- failed = []
- for pkgname, vstring, vinfo in needed_packages:
- logging.info('\trtremove: remove package %s for %s' % (pkgname, self.rtname))
- pkg = DebPackage('package', pkgname)
- pkg.set_version_field(vstring)
- try:
- pkg.set_default_runtime_from_version_info()
- except ValueError:
- # original runtime is already removed, use the default for removal
- pkg.default_runtime = get_default_runtime()
- try:
- pkg.remove([self.runtime], remove_script_files=False)
- except PyCentralError, msg:
- self.error('failed to remove %s support for package %s' % (self.rtname, pkgname), go_on=True)
- failed.append(pkgname)
- if failed:
- self.error('failed to remove %s support for %d packages' % len(failed))
-
- register_action(ActionRuntimeRemove)
-
-
- class ActionUpdateDefault(Action):
- name = 'updatedefault'
- help = 'update the default python version'
- usage = '<old runtime> <new runtime>'
-
- def check_args(self, global_options):
- if len(self.args) != 2:
- self._option_parser.print_help()
- sys.exit(1)
- self.oldrtname = self.args[0]
- self.rtname = self.args[1]
- packages = read_dpkg_status()
- self.needed_packages = []
- for pkgname, vstring in packages:
- if vstring.find('current') == -1:
- continue
- try:
- versions = pyversions.requested_versions(vstring, version_only=True)
- except ValueError:
- self.error("package %s is not ready to be updated for %s"
- % (pkgname, self.rtname))
- continue
- pkg = DebPackage('package', pkgname)
- self.needed_packages.append(pkg)
- return self.errors_occured
-
- def run(self, global_options):
- logging.info('\tupdate default: update %d packages for %s'
- % (len(self.needed_packages), self.rtname))
- runtimes = get_installed_runtimes()
- default_rt = get_default_runtime()
- bc_option = get_debian_config().get('DEFAULT', 'byte-compile')
- try:
- for pkg in self.needed_packages:
- pkg.read_version_info()
- pkg.set_default_runtime_from_version_info()
- if pkg.shared_files or pkg.private_files:
- pkg.update_bytecode_files(runtimes, default_rt, bc_option)
- except PyCentralError, msg:
- self.error(msg)
-
- register_action(ActionUpdateDefault)
-
-
- class ActionList(Action):
- name = 'list'
- help = 'List all pycentral-managed files'
-
- def check_args(self, global_options):
- if len(self.args) != 0:
- self._option_parser.print_help()
- sys.exit(1)
- return self.errors_occured
-
- def run(self, global_options):
- runtimes = get_installed_runtimes(with_unsupported=True)
- for (p, v) in read_dpkg_status():
- pkg = DebPackage('package', p)
- pkg.read_version_info()
- for f in pkg.list(runtimes, list_script_files=True):
- print f
-
- register_action(ActionList)
-
-
- class ActionShowDefault(Action):
- name = 'showdefault'
- help = 'Show default python version number'
-
- def check_args(self, global_options):
- if len(self.args) != 0:
- self._option_parser.print_help()
- sys.exit(1)
- return self.errors_occured
-
- def run(self, global_options):
- print pyversions.default_version(version_only=True)
- sys.stderr.write("pycentral showdefault is deprecated, use `pyversions -vd'\n")
-
- register_action(ActionShowDefault)
-
-
- class ActionShowVersions(Action):
- name = 'showversions'
- help = 'Show version numbers of supported python versions'
-
- def check_args(self, global_options):
- if len(self.args) != 0:
- self._option_parser.print_help()
- sys.exit(1)
-
- return self.errors_occured
-
- def run(self, global_options):
- supported = pyversions.supported_versions()
- versions = [d[6:] for d in supported if re.match(r'python\d\.\d', d)]
- print ' '.join(versions)
- sys.stderr.write("pycentral showversions is deprecated, use `pyversions -vs'\n")
-
- register_action(ActionShowVersions)
-
- class ActionShowSupported(Action):
- name = 'showsupported'
- help = 'Show the supported python versions'
-
- def check_args(self, global_options):
- if len(self.args) != 0:
- self._option_parser.print_help()
- sys.exit(1)
- return self.errors_occured
-
- def run(self, global_options):
- supported = pyversions.supported_versions()
- print ' '.join(supported)
- sys.stderr.write("pycentral showsupported is deprecated, use `pyversions -s'\n")
-
- register_action(ActionShowSupported)
-
-
- class ActionPyCentralDir(Action):
- name = 'pycentraldir'
- help = 'Show the pycentral installation directory for the package'
- usage = '<package>'
-
- def check_args(self, global_options):
- if len(self.args) != 1:
- self._option_parser.print_help()
- sys.exit(1)
- self.pkgname = self.args[0]
- return self.errors_occured
-
- def run(self, global_options):
- if shared_base2[-1] == '/':
- print shared_base2[:-1]
- else:
- print shared_base2
-
- register_action(ActionPyCentralDir)
-
-
- class ActionVersion(Action):
- name = 'version'
- help = 'Show the pycentral version'
-
- def check_args(self, global_options):
- if len(self.args) != 0:
- self._option_parser.print_help()
- sys.exit(1)
-
- return self.errors_occured
-
- def run(self, global_options):
- sys.stdout.write("%s\n" % pycentral_version)
-
- register_action(ActionVersion)
-
-
- class ActionDebhelper(Action):
- name = 'debhelper'
- help = 'move files to pycentral location, variable substitutions'
- usage = '[-p|--provides] [--no-move|--include-links] <package> [<package directory>]'
-
- def get_option_parser(self):
- if not self._option_parser:
- envvar = os.environ.get('DH_PYCENTRAL', '')
- substvars_default = 'no'
- if 'substvars=file' in envvar:
- substvars_default = 'file'
- if 'substvars=stdout' in envvar:
- substvars_default = 'stdout'
-
- p = OptionParser()
- p.add_option('-p', '--provides',
- help="generate substitution for python:Provides",
- default='add-provides' in envvar, action='store_true', dest='provides')
- p.add_option('--no-move', '--nomove',
- help="do not move files to pycentral location",
- default='no-move' in envvar or 'nomove' in envvar, action='store_true', dest='nomove')
- p.add_option('--include-links',
- help="include links to the pycentral location",
- default='include-links' in envvar, action='store_true', dest='includelinks')
- p.add_option('--stdout',
- help="just print substitution variables to stdout",
- default='stdout' in envvar, action='store_true', dest='stdout')
- p.add_option('--substvars',
- help="where to print substitution vars (no, file, stdout)",
- default=substvars_default, dest='substvars')
- p.add_option('--no-act', '--dry-run',
- help="dry run",
- default=('dry-run' in envvar) or ('no-act' in envvar),
- action='store_true', dest='dryrun')
- self._option_parser = p
- return self._option_parser
-
- def check_args(self, global_options):
- if not len(self.args) in (1, 2):
- self._option_parser.print_help()
- sys.exit(1)
- if 'file' in self.options.substvars:
- self.options.substvars = 'file'
- if 'stdout' in self.options.substvars:
- self.options.substvars = 'stdout'
- if self.options.nomove and self.options.includelinks:
- self.error("options `--no-move' and `--include-links' conflict")
- return self.errors_occured
-
- def run(self, global_options):
- if len(self.args) < 2:
- pkgdir = 'debian/' + self.args[0]
- else:
- pkgdir = self.args[1]
- try:
- pkg = DebPackage('package', self.args[0], pkgdir=pkgdir,
- parse_versions=self.options.substvars!='no')
- if not self.options.nomove:
- pkg.move_files()
- if self.options.includelinks:
- pkg.add_shared_links()
- pkg.read_pyfiles()
- if self.options.substvars!='no':
- pkg.gen_substvars()
- except PyCentralVersionMissingError, msg:
- self.warn(msg)
- return
- except PyCentralError, msg:
- self.error(msg)
-
- out = None
- if self.options.stdout or self.options.substvars == 'stdout':
- out = sys.stdout
- elif self.options.substvars == 'file':
- out = file('debian/%s.substvars' % pkg.name, 'a+')
- if out:
- out.write('python:Versions=%s\n' % pkg.version_field)
- out.write('python:Depends=%s\n' % pkg.depends)
- out.write('python:Provides=%s\n' % pkg.provides)
-
-
- register_action(ActionDebhelper)
-
- # match a string with the list of available actions
- def action_matches(action, actions):
- prog = re.compile('[^-]*?-'.join(action.split('-')))
- return [a for a in actions if prog.match(a)]
-
- def usage(stream, msg=None):
- print >>stream, msg
- print >>stream, "use `%s help' for help on actions and arguments" % program
- print >>stream
- sys.exit(1)
-
- # parse command line arguments
- def parse_options(args):
- shortusage = 'usage: %s [<option> ...] <action> <pkgname>' % program
- parser = OptionParser(usage=shortusage)
- parser.disable_interspersed_args()
-
- # setup the parsers object
- parser.remove_option('-h')
- parser.add_option('-h', '--help',
- help='help screen',
- action='store_true', dest='help')
- parser.add_option('-v', '--verbose',
- help='verbose mode',
- action='store_true', dest='verbose')
-
- global_options, args = parser.parse_args()
- # Print the help screen and exit
- if len(args) == 0 or global_options.help:
- parser.print_help()
- print "\nactions:"
- action_names = known_actions.keys()
- action_names.sort()
- for n in action_names:
- print " %-21s %s" % (n, known_actions[n].help)
- print ""
- sys.exit(1)
-
- # check if the specified action really exists
- action_name = args[0]
- del args[0]
- matching_actions = action_matches(action_name, known_actions.keys())
- if len(matching_actions) == 0:
- usage(sys.stderr, "unknown action `%s'" % action_name)
- elif len(matching_actions) > 1:
- usage(sys.stderr,
- "ambiguous action `%s', matching actions: %s"
- % (action_name, strlist(matching_actions)))
- else:
- action_name = matching_actions[0]
-
- # instantiate an object for the action and parse the remaining arguments
- action = known_actions[action_name]()
- action_options, action_names = action.parse_args(args)
-
- return global_options, action
-
- class Logging:
- DEBUG, INFO, WARN, ERROR = range(4)
- def __init__(self, level=WARN):
- self.fd = None
- self.level = level
- try:
- self.fd = file('/var/log/pycentral.log', 'a+')
- except IOError:
- self.fd = None
- def msg(self, level, s):
- if level < self.level:
- return
- d = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
- if self.fd:
- self.fd.write('%s %s %s\n' % (d, level, s))
- self.fd.flush()
- sys.stdout.write('pycentral: %s\n' % (s))
- sys.stdout.flush()
- def info(self, s):
- self.msg(self.INFO, s)
- def warn(self, s):
- self.msg(self.WARN, s)
- def error(self, s):
- self.msg(self.ERROR, s)
- sys.stderr.write('%s\n' % s)
- def debug(self, s):
- self.msg(self.DEBUG, s)
-
- def debug_list(self, tab, s, l, n=4):
- l2 = l[:min(n, len(l))]
- if len(l) > n:
- l2.append('...')
- self.msg(self.DEBUG, "%s%s (%s/%s)" % (tab, s, len(l2), len(l)))
- if len(l2) > 0:
- logging.debug('%s %s' % (tab, l2))
-
- def setup_logging(loglevel=Logging.WARN, verbose=False):
- levels = ['debug', 'info', 'warn', 'error']
- env_level = os.environ.get('PYCENTRAL', 'warn').lower()
- for i in range(len(levels)):
- if env_level.find(levels[i]) != -1:
- loglevel = i
- if verbose:
- loglevel = Logging.DEBUG
- global logging
- logging = Logging(loglevel)
-
- def main():
- global_options, action = parse_options(sys.argv[1:])
-
- os.umask(0022)
-
- # setup logging stuff
- setup_logging(Logging.WARN, global_options.verbose)
- if action.name == 'debhelper' or action.name.startswith('show'):
- pass
- else:
- logging.debug('pycentral ' + ' '.join(sys.argv[1:]))
-
- # check the arguments according to the action called
- if action.check_args(global_options):
- sys.exit(1)
-
- # run the action and exit
- rv = action.run(global_options)
- sys.exit(rv)
-
-
- # call the main routine
- if __name__ == '__main__':
- main()
-